/*
 * @(#)VsnetMetalProgressBarUI.java 6/21/2005
 *
 * Copyright 2002 - 2005 JIDE Software Inc. All rights reserved.
 */
package com.element.plaf.vsnet;

import com.element.plaf.UIDefaultsLookup;
import com.element.util.UIUtil;

import javax.swing.*;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.metal.MetalProgressBarUI;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;

/**
 * A better ProgressBarUI for indeterminate progress bar.
 * <p/>
 * v * <b>Credit:</b> This implementation is based on work from Santhosh Kumar - santhosh@in.fiorano.com.
 */

public class VsnetMetalProgressBarUI extends MetalProgressBarUI implements ActionListener {
	/**
	 * Interval (in ms) between repaints of the indeterminate progress bar.
	 * The value of this method is set
	 * (every time the progress bar changes to indeterminate mode)
	 * using the
	 * "ProgressBar.repaintInterval" key in the defaults table.
	 */
	private int repaintInterval;

	private int x = 0, y = 0, delta = 1;
	private Timer timer = null;


	public static ComponentUI createUI(JComponent x) {
		return new VsnetMetalProgressBarUI();
	}

	@Override
	protected void installDefaults() {
		super.installDefaults();
		initRepaintInterval(); //initialize repaint interval
	}

	@Override
	protected void startAnimationTimer() {
		if (timer == null) {
			timer = new Timer(getRepaintInterval() / 20, this);
		}
		x = y = 0;
		delta = 1;
		timer.start();
	}

	@Override
	protected void stopAnimationTimer() {
		if (timer != null) {
			timer.stop();
		}
	}

	public void actionPerformed(ActionEvent ae) {
		// style1
		if (x == 0)
			delta = 1;
		else if (x == progressBar.getWidth())
			delta = -1;
		x += delta;

		progressBar.repaint();
	}

	/**
	 * Returns the desired number of milliseconds between repaints.
	 * This value is meaningful
	 * only if the progress bar is in indeterminate mode.
	 * The repaint interval determines how often the
	 * default animation thread's timer is fired.
	 * It's also used by the default indeterminate progress bar
	 * painting code when determining
	 * how far to move the bouncing box per frame.
	 * The repaint interval is specified by
	 * the "ProgressBar.repaintInterval" UI default.
	 *
	 * @return the repaint interval, in milliseconds
	 */
	protected int getRepaintInterval() {
		return repaintInterval;
	}

	private int initRepaintInterval() {
		repaintInterval = UIDefaultsLookup.getInt("ProgressBar.repaintInterval");
		return repaintInterval;
	}

	private Rectangle boxRect;

	@Override
	public void paintIndeterminate(Graphics g, JComponent c) {
		super.paintDeterminate(g, c);

		if (!(g instanceof Graphics2D g2d)) {
			return;
		}

		Color startColor = progressBar.getForeground();
		Color endColor = VsnetUtils.getLighterColor(startColor, 0.9f);

		Insets b = progressBar.getInsets(); // area for border
		int barRectWidth = progressBar.getWidth() - (b.right + b.left);
		int barRectHeight = progressBar.getHeight() - (b.top + b.bottom);

		// Paint the bouncing box.
		boolean isVertical = c.getHeight() > c.getWidth();
		if (delta > 0) {
			boxRect = new Rectangle(0, 0, x, progressBar.getHeight() - 1);
			UIUtil.fillNormalGradient(g2d, boxRect, endColor, startColor, isVertical);
		} else {
			boxRect = new Rectangle(x, 0, progressBar.getWidth() - x, progressBar.getHeight() - 1);
			UIUtil.fillNormalGradient(g2d, boxRect, startColor, endColor, isVertical);
		}

		// Deal with possible text painting
		if (progressBar.isStringPainted()) {
			if (progressBar.getOrientation() == JProgressBar.HORIZONTAL) {
				paintString(g2d, b.left, b.top,
						barRectWidth, barRectHeight,
						boxRect.x, boxRect.width, b);
			} else {
				paintString(g2d, b.left, b.top,
						barRectWidth, barRectHeight,
						boxRect.y, boxRect.height, b);
			}
		}
	}

	/**
	 * Paints the progress string.
	 *
	 * @param g          Graphics used for drawing.
	 * @param x          x location of bounding box
	 * @param y          y location of bounding box
	 * @param width      width of bounding box
	 * @param height     height of bounding box
	 * @param fillStart  start location, in x or y depending on orientation,
	 *                   of the filled portion of the progress bar.
	 * @param amountFull size of the fill region, either width or height
	 *                   depending upon orientation.
	 * @param b          Insets of the progress bar.
	 */
	private void paintString(Graphics g, int x, int y, int width, int height,
	                         int fillStart, int amountFull, Insets b) {
		if (!(g instanceof Graphics2D g2)) {
			return;
		}

		String progressString = progressBar.getString();
		g2.setFont(progressBar.getFont());
		Point renderLocation = getStringPlacement(g2, progressString, x, y, width, height);
		Rectangle oldClip = g2.getClipBounds();

		if (progressBar.getOrientation() == JProgressBar.HORIZONTAL) {
			g2.setColor(getSelectionBackground());
			UIUtil.drawString(g2, progressString, renderLocation.x, renderLocation.y);
			g2.setColor(getSelectionForeground());
			g2.clipRect(fillStart, y, amountFull, height);
			UIUtil.drawString(g2, progressString, renderLocation.x, renderLocation.y);
		} else { // VERTICAL
			g2.setColor(getSelectionBackground());
			AffineTransform rotate = AffineTransform.getRotateInstance(Math.PI / 2);
			g2.setFont(progressBar.getFont().deriveFont(rotate));
			renderLocation = getStringPlacement(g2, progressString, x, y, width, height);
			UIUtil.drawString(g2, progressString, renderLocation.x, renderLocation.y);
			g2.setColor(getSelectionForeground());
			g2.clipRect(x, fillStart, width, amountFull);
			UIUtil.drawString(g2, progressString, renderLocation.x, renderLocation.y);
		}
		g2.setClip(oldClip);
	}


	public static void main(String[] args) {
		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (Exception e) {
			e.printStackTrace();
		}
		JProgressBar progressBar = new JProgressBar();
		JProgressBar myProgressBar = new JProgressBar();
		myProgressBar.setUI(new VsnetMetalProgressBarUI());
		progressBar.setIndeterminate(true);
		progressBar.setString("Percent");
		progressBar.setStringPainted(true);
		myProgressBar.setIndeterminate(true);
		myProgressBar.setString("Percent");
		myProgressBar.setStringPainted(true);
		JPanel panel = new JPanel(new BorderLayout(5, 5));
		panel.add(progressBar, BorderLayout.NORTH);
		panel.add(myProgressBar, BorderLayout.SOUTH);
		JOptionPane.showMessageDialog(null, panel, "ProgressBars made intutive - santhosh@in.fiorano.com", JOptionPane.INFORMATION_MESSAGE);
		System.exit(0);
	}
}